package com.mcflywzx.airhockey;
import static android.opengl.GLES20.GL_COLOR_BUFFER_BIT;
import static android.opengl.GLES20.GL_DEPTH_BUFFER_BIT;
import static android.opengl.GLES20.GL_DEPTH_TEST;
import static android.opengl.GLES20.glClear;
import static android.opengl.GLES20.glClearColor;
import static android.opengl.GLES20.glEnable;
import static android.opengl.GLES20.glViewport;
import static android.opengl.Matrix.*;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

import android.content.Context;
import android.opengl.GLSurfaceView.Renderer;

import com.mcflywzx.airhockey.objects.Mallet;
import com.mcflywzx.airhockey.objects.*;
import com.mcflywzx.airhockey.objects.Text;
import com.mcflywzx.airhockey.programs.ColorShaderProgram;
import com.mcflywzx.airhockey.programs.TextureShaderProgram;
import com.mcflywzx.airhockey.util.Geometry.*;
import com.mcflywzx.airhockey.util.Geometry;
import com.mcflywzx.airhockey.util.Tools;
import com.mcflywzx.airhockey.util.MatrixHelper;
import com.mcflywzx.airhockey.util.TextureHelper;
import com.mcflywzx.airhockey.objects.*;

public class AirHockeyRenderer implements Renderer {
	
	private final float[] invertedViewProjectionMatrix = new float[16];

	private final Context context;

	MatrixHelper mh = new MatrixHelper();
	
	private MCube c;
	private MCube player;
	
	private int FPS = 0;
	
	private Mallet mallet;
		private float malletSpeed;
	private MCylinder puck;
		private Point puckPosition;
		private Vector puckVector;
	private Text testText;
	
	float dPM;
	
	private boolean malletPressed = false;
	private Point blueMalletPosition;
	private Point previousBlueMalletPosition;
	
	private TextureShaderProgram tsp;
	private ColorShaderProgram csp;
	
	private int tex;
	
	float ST, DT;
	String[] TouchLog = new String[]{"Wellcome", "to OpenGL ES", "World >_<"};
	
	public AirHockeyRenderer(Context context) //构造函数
	{
		this.context = context;
	}
	
	@Override
	public void onSurfaceCreated(GL10 glUnused, EGLConfig config) {
		// TODO Surface创建时调用
		glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
		glEnable(GL_DEPTH_TEST);
		
		
		testText = new Text(0.8f, 0.2f, TouchLog);
		mallet = new Mallet(0.08f, 0.15f, 32);
		//puck = new MCylinder(0.06f, 0.02f, 32);
		
		//puckPosition = new Point(0f, puck.H / 2, 0f);
		//puckVector = new Vector(0f, 0f, 0f);
		
		tsp = new TextureShaderProgram(context);
		csp = new ColorShaderProgram(context);
		
		//s = new MSquare(new Point(0.2f, 0.2f, 0.2f), 0.2f, 0.2f, csp);
		
		c = new MCube(new Point(0f, -0.2f, 0f), 0.4f, 0.7f, 0.5f, mh, tsp, context);
		player = new MCube(new Point(0f, 0.2f, 0f), 0.2f, 0.2f, 0.4f, mh, tsp, context);
		//tex = TextureHelper.loadTexture(context, R.drawable.air_hockey_surface);
		
		blueMalletPosition = new Point(0f, mallet.H / 2f, 0.4f);
		previousBlueMalletPosition = blueMalletPosition;
		
		ST = System.nanoTime();
		DT = ST;
	}
	
	@Override
	public void onSurfaceChanged(GL10 glUnused, int width, int height) {
		// TODO 设置使OpenGL视口充满整个表面
		glViewport(0, 0, width, height);
		//创建一个透视投影矩阵
		mh.initializeCameraMatrix(width, height);
		
	}
	
	/*void logic() {
		dPM = Geometry.vectorBetween(blueMalletPosition, puckPosition).length();
		malletSpeed = Geometry.vectorBetween(previousBlueMalletPosition, blueMalletPosition).length();
		
		if(dPM < (puck.R + mallet.R)) {
			//Tools.ToastLog(context, "knockout");
			puckVector = Geometry.vectorBetween(blueMalletPosition, puckPosition);
			puckVector = puckVector.scale(malletSpeed * 10 + puckVector.length() / 7);
		}
		
		puckPosition = puckPosition.translate(puckVector);
		puckPosition = puckPosition.setY(puck.H / 2);
		
		if(puckPosition.x < table.leftBound + puck.R || puckPosition.x > table.rightBound - puck.R) {
			puckVector = new Vector(-puckVector.x, puckVector.y, puckVector.z);
			puckVector = puckVector.scale(0.9f);
		}
		if(puckPosition.z < table.farBound + puck.R || puckPosition.z > table.nearBound - puck.R) {
			puckVector = new Vector(puckVector.x, puckVector.y, -puckVector.z);
			puckVector = puckVector.scale(0.9f);
		}
		
		puckPosition = new Point(
				Tools.clamp(puckPosition.x, table.leftBound + puck.R, table.rightBound - puck.R),
				puckPosition.y,
				Tools.clamp(puckPosition.z, table.farBound + puck.R, table.nearBound - puck.R));
		
		puckVector = puckVector.scale(0.99f);
	}*/
	
	int drawN = 0;

	Vector sp = new Vector(0f, 0f, 0f);
	
	float T = 0;
	
	void logic() {
		
		if(System.nanoTime() - DT > 1000000000) {
			FPS = drawN;
			DT = System.nanoTime();
			drawN = 0;
		}
		
		if(player.position.y - c.position.y <= (c.H + player.H)/2) {
			if(sp.y < 0) {
				sp.y = 0;
			}
		} else {
			sp.y += -0.0098f;
			
		}
		
		player.addVector(sp);
		
	}
	
	@Override
	public void onDrawFrame(GL10 glUnused) {
		// TODO Auto-generated method stub
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
		mh.setCamera(new Point(player.position.x, 1f, 3.5f));
		mh.initializeScene();
		
		if(System.nanoTime() - T > 10000000) {
			T = System.nanoTime();
			logic();
		}
		
		c.position.x = player.position.x;
		
		c.draw();
		player.draw();
		//mh.PositionAndRotateCubeInScene(c);
		
		
		/*mh.PositionAndRotateObjectInScene(0f, mallet.H / 2f, -0.4f);
		csp.useProgram();
		csp.setUniforms(mh.modelViewProjectionMatrix, 1f, 0f, 0f);
		mallet.bindData(csp);
		mallet.draw();*/
		
		/*PositionAndRotateObjectInScene(blueMalletPosition.x, blueMalletPosition.y, blueMalletPosition.z);
		csp.setUniforms(modelViewProjectionMatrix, 0f, 0f, 1f);
		mallet.draw();*/
		
		
		
		
		/*PositionAndRotateObjectInScene(puckPosition.x, puckPosition.y, puckPosition.z);
		csp.setUniforms(modelViewProjectionMatrix, 0.8f, 0.8f, 1f);
		puck.bindData(csp);
		puck.draw();*/

		mh.PositionAndRotateObjectInScene(player.position.x, 0.5f, 0f);
		tsp.useProgram();
		tsp.setUniforms(mh.modelViewProjectionMatrix, testText.setTextTex(new String[]{"FPS：" + FPS, sp.y + "", player.position.x + ""}));
		testText.bindData(tsp);
		testText.draw();
		//s.draw(mh.modelViewProjectionMatrix);
		drawN += 1;
	}
	
	

	public void TPress(float X, float Y) {
		/*
		Ray ray = twoDPointToRay(X, Y);
		
		Sphere mallteBoundingSphere = new Sphere(new Point(
						blueMalletPosition.x,
						blueMalletPosition.y,
						blueMalletPosition.z),
				mallet.H / 2f);
		
		malletPressed = Geometry.intesects(mallteBoundingSphere, ray);
		*/
		//TouchLog[0] = "点中了mallet?" + malletPressed;
		TouchLog[1] =  "X:" + X;
		TouchLog[2] =  "Y:" + Y;
		if(X < 0 && Y < 0) {
			sp.x = 0.01f;
		} else {
			sp.x = 0;
		}
		//sp.y += 0.1f;
		//sp.x = 0.01f;
	}
	
	public void TDrag(float X, float Y) {
		/*if(malletPressed) {
			Ray ray = twoDPointToRay(X, Y);
			
			Plane plane = new Plane(new Point(0, 0, 0), new Vector(0, 1, 0));
			
			Point touchedPoint = Geometry.intersectionPoint(ray, plane);
			
			previousBlueMalletPosition = blueMalletPosition;
			blueMalletPosition = new Point(
					Tools.clamp(touchedPoint.x, table.leftBound + mallet.R, table.rightBound - mallet.R), 
					mallet.H / 2f, 
					Tools.clamp(touchedPoint.z, 0f + mallet.R, table.nearBound - mallet.R));
		
			TouchLog[0] = "拖动mallet中";
			TouchLog[1] =  "X:" + touchedPoint.x;
			TouchLog[2] =  "Y:" + touchedPoint.z;
		} else {*/			
			TouchLog[0] = "TouchDrag";
			TouchLog[1] =  "X:" + X;
			TouchLog[2] =  "Y:" + Y;
		//}
		//sp.y += 0.1;
	}
	
	public void NoneTouch() {
		TouchLog[0] = "NoTouch";
	}
	
	private Ray twoDPointToRay(float x, float y) {
		final float[] nearPointNdc = {x, y, -1, 1};
		final float[] farPointNdc = {x, y, 1, 1};
		
		final float[] nearPointWorld = new float[4];
		final float[] farPointWorld = new float[4];
		
		multiplyMV(nearPointWorld, 0, invertedViewProjectionMatrix, 0, nearPointNdc, 0);
		multiplyMV(farPointWorld, 0, invertedViewProjectionMatrix, 0, farPointNdc, 0);
		
		divideByW(nearPointWorld);
		divideByW(farPointWorld);
		
		Point nearPointRay = new Point(nearPointWorld[0], nearPointWorld[1], nearPointWorld[2]);
		Point farPointRay = new Point(farPointWorld[0], farPointWorld[1], farPointWorld[2]);
		
		return new Ray(nearPointRay, Geometry.vectorBetween(nearPointRay, farPointRay));
	}
	
	private void divideByW(float[] vector) {
		vector[0] /= vector[3];
		vector[1] /= vector[3];
		vector[2] /= vector[3];
	}
}
